<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <canvas id="canvas" width=400 height=400></canvas>
</body>
</html>
<script>
   /** @type {HTMLCanvasElement} */
   let canvas = document.getElementById('canvas');
  let gl = canvas.getContext('webgl');
  gl.clearColor(0.1, 0.5, 0.4, 0.3);
  gl.clear(gl.COLOR_BUFFER_BIT);

  function initShader(gl, vertexSource, fragmentSource) {
    // 创造着色器对象
    let vertexShader = gl.createShader(gl.VERTEX_SHADER);
    let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(vertexShader, vertexSource);
    gl.shaderSource(fragmentShader, fragmentSource)
    gl.compileShader(vertexShader);
    gl.compileShader(fragmentShader);
    let program = gl.createProgram();
    gl.attachShader(program, vertexShader)
    gl.attachShader(program, fragmentShader)
    gl.linkProgram(program);
    gl.useProgram(program);
    return program
  }
  
  let vertexSource = `
    //attribute声明vec4类型变量position
    attribute vec4 position;

    // attribute声明顶点颜色变量
    attribute vec4 color;

    //顶点法向量
    attribute vec4 normal;

    // 光照颜色  跟模型相关和光照相关的 我们都用 uniform声明变量
    uniform vec3 light_color;

    // 光照方向
    uniform vec3 light_direction;

    //varying声明顶点颜色插值后变量
    varying vec4 vv_color;


    void main() {
      // 顶点坐标position赋值给内置变量gl_Position
      float r = radians(30.0);
      float cos = cos(r);
      float sin = sin(r);
      // 绕x旋转
      mat4 mx = mat4(1,0,0,0, 0,cos,-sin,0, 0,sin,cos,0, 0,0,0,1);
      // 绕y旋转
      mat4 my = mat4(cos,0,-sin,0, 0,1,0,0, sin,0,cos,0, 0,0,0,1);
      // 绕z旋转
      mat4 mz = mat4(cos,sin,0,0, -sin,cos,0,0, 0,0,1,0, 0,0,0,1);
      gl_Position = mx*my*position;

      // 由于我们的物体旋转了 那么每个面的法向量也要跟着旋转
      vec3 normal2 = normalize((mx*my*normal).xyz);

      // 光照方向归一化
      vec3 light_direction2 = normalize(light_direction);

      // 这个就是光线的方向和顶点法向量的点积 其实就是cos
      float dot = max(-dot(light_direction2,normal2),0.0);

      // 算出反射的光线的颜色
      vec3 reflectColor = color.rgb * light_color * dot;



      //顶点颜色插值计算
      //vv_color = color;
      vv_color = vec4(reflectColor,color.a);
    }
  `
  let fragmentSource = `
    // 所有float类型数据的精度是lowp  lowp   ：精确度低;mediump：精确度中;highp  ：精确度高
    precision lowp float;
    // 接收顶点着色器中v_color数据
    varying vec4 vv_color;
    void main() {
      // 插值后颜色数据赋值给对应的片元
      gl_FragColor = vv_color;
    }
  `
  let program = initShader(gl, vertexSource, fragmentSource);
  let position = gl.getAttribLocation(program,'position');
  let color = gl.getAttribLocation(program,'color');
  let normal = gl.getAttribLocation(program,'normal');
  
  let light_color = gl.getUniformLocation(program,'light_color');
  let light_direction = gl.getUniformLocation(program,'light_direction');

  gl.uniform3f(light_color,1.0,1.0,1.0)
  gl.uniform3f(light_direction,-1,-2,10) // 把我们设置的光照方向理解成 光源的方向


  /**
  创建顶点位置数据数组data,Javascript中小数点前面的0可以省略
  **/
  var data=new Float32Array([
      .5,.5,.5,-.5,.5,.5,-.5,-.5,.5,.5,.5,.5,-.5,-.5,.5,.5,-.5,.5,      //面1
      .5,.5,.5,.5,-.5,.5,.5,-.5,-.5,.5,.5,.5,.5,-.5,-.5,.5,.5,-.5,      //面2
      .5,.5,.5,.5,.5,-.5,-.5,.5,-.5,.5,.5,.5,-.5,.5,-.5,-.5,.5,.5,      //面3
      -.5,.5,.5,-.5,.5,-.5,-.5,-.5,-.5,-.5,.5,.5,-.5,-.5,-.5,-.5,-.5,.5,//面4
      -.5,-.5,-.5,.5,-.5,-.5,.5,-.5,.5,-.5,-.5,-.5,.5,-.5,.5,-.5,-.5,.5,//面5
      .5,-.5,-.5,-.5,-.5,-.5,-.5,.5,-.5,.5,-.5,-.5,-.5,.5,-.5,.5,.5,-.5 //面6
  ]);


  /**
 创建顶点颜色数组colorData
 **/
var colorData = new Float32Array([
    1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,//红色——面1
    1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,//红色——面1
    1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,//红色——面1
    1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,//红色——面1
    1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,//红色——面1
    1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0, 1,0,0,//红色——面1
]);

/**
 *顶点法向量数组normalData
 **/
 var normalData = new Float32Array([
    0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,//z轴正方向——面1
    1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,//x轴正方向——面2
    0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,//y轴正方向——面3
    -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,//x轴负方向——面4
    0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,//y轴负方向——面5
    0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1//z轴负方向——面6
]);

let normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER,normalData,gl.STATIC_DRAW);
gl.vertexAttribPointer(normal,3,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(normal);


let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
gl.vertexAttribPointer(position,3,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(position);


let colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,colorData,gl.STATIC_DRAW);
gl.vertexAttribPointer(color,3,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(color);

gl.enable(gl.DEPTH_TEST);// 
gl.drawArrays(gl.TRIANGLES,0,36)
</script>